from __future__ import annotations
import csv
from pathlib import Path
from .base_structure import Item_Factory, Transaction
from typing import Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from .base_structure import Item
    from .cli import Setting


class Tagger:
    def __init__(self, item_name_tags_map: Optional[dict[str, set[str]]]=None, index_tags_map: Optional[dict[int, set[str]]]=None) -> None:
        self.tags: list[str] = []
        self.item_name_tags_map = item_name_tags_map
        self.index_tags_map = index_tags_map

    def set_item_name_tags_map(self, item_name_tags_map: dict[str, set]) -> Tagger:
        self.item_name_tags_map = item_name_tags_map
        return self

    def set_index_tags_map(self, index_tags_map: dict[int, set[str]]) -> Tagger:
        self.index_tags_map = index_tags_map
        return self 

    def get_tags(self, index: int, item_name: str) -> frozenset[str]:
        tags: set[str] = set()
        if self.index_tags_map is not None:
            _tags = self.index_tags_map.get(index)
            if _tags is not None:
                tags |= set(_tags)
        if self.item_name_tags_map is not None:
            _tags = self.item_name_tags_map.get(item_name)
            if _tags is not None:
                tags |= set(_tags)
        return frozenset(tags)


class Data_Assistant:
    def __init__(self) -> None:
        self.item_frequency: dict[Item, int] = {}
        self.tag_frequency: dict[str, int] = {}
        self.name_map: dict[str, str] = {}
        self.data_len = 0

    def form_data(self, data: list[list[str]], item_factory: Item_Factory, tagger: Tagger, setting: Setting) -> list[Transaction]:
        self.item_frequency = {}
        self.tag_frequency = {}
        self.data_len = 0
        
        new_data: list[Transaction] = []
        if setting.data_form != 'RDB-like':
            for row in data:
                transaction = Transaction()
                contain_tags: set[str] = set()
                for index, cell in enumerate(row):
                    if (cell != '') and (index in setting.all_data_index):
                        if setting.data_form == 'excel-like':
                            item_name = cell
                            if item_name in self.name_map:
                                item_name = self.name_map[item_name]
                            tags = tagger.get_tags(index, item_name)
                            if tags is not None:
                                contain_tags |= tags
                            item = item_factory.get_item(item_name, tags)
                            transaction.append(item)
                        else:
                            items_name = cell 
                            for item_name in items_name.split(','):
                                item_name = item_name.strip()
                                if item_name in self.name_map:
                                    item_name = self.name_map[item_name]
                                tags = tagger.get_tags(index, item_name)
                                if tags is not None:
                                    contain_tags |= tags
                                item = item_factory.get_item(item_name, tags)
                                transaction.append(item)
                for tag in contain_tags:
                    if tag in self.tag_frequency:
                        self.tag_frequency[tag] += 1
                    else:
                        self.tag_frequency[tag] = 1
                new_data.append(transaction.unique())
        else:
            data_id_index = setting.data_id_index
            data_indexs = setting.all_data_index - {data_id_index}
            data_dict: dict[str, set[Item]] = {}
            for row in data:
                data_id = row[data_id_index]
                for index in data_indexs:
                    if row[index] != '':
                        item_name = row[index]
                        if item_name in self.name_map:
                            item_name = self.name_map[item_name]
                        tags = tagger.get_tags(index, item_name)
                        data_dict.setdefault(data_id, set()).add(item_factory.get_item(item_name, tags))
            for _, items in data_dict.items():
                contain_tags: set[str] = set()
                transaction = Transaction()
                for item in items:
                    transaction.append(item)
                    contain_tags |= set(item.item_tags)
                for tag in contain_tags:
                    if tag in self.tag_frequency:
                        self.tag_frequency[tag] += 1
                    else:
                        self.tag_frequency[tag] = 1
                new_data.append(transaction.unique())
        self.data_len = len(new_data)
        return new_data


    def form_name_map(self, data: list[list[str]], setting: Setting) -> None:
        if setting.absolute_name_map_file.exists():
            raise Exception(f'{setting.absolute_name_map_file}已存在, 为防止误覆盖数据, 请修改文件名或setting中name_map_file属性')
        output: list[list[str]] = [['原名', '频数', '目标名', '标签']]
        item_frequency: dict[str, int] = {}
        data_indexs = setting.all_data_index
        if setting.data_form == 'RDB-like':
            data_id_index = setting.data_id_index
            data_indexs = data_indexs - {data_id_index}
            data_dict: dict[str, set[str]] = {}
            for row in data:
                data_id = row[data_id_index]
                for index in data_indexs:
                    if row[index] != '':
                        data_dict.setdefault(data_id, set()).add(row[index])
            for _, items_name in data_dict.items():
                for item_name in items_name:
                    if item_name in item_frequency:
                        item_frequency[item_name] += 1
                    else:
                        item_frequency[item_name] = 1

        elif setting.data_form == 'excel-like':
            for row in data:
                items_name = set()
                for index in data_indexs:
                    if row[index] != '':
                        items_name.add(row[index])
                for item_name in items_name:
                    if item_name in item_frequency:
                        item_frequency[item_name] += 1
                    else:
                        item_frequency[item_name] = 1

        elif setting.data_form == 'excel-like-incell':
            for row in data:
                items_name = set()
                for index in data_indexs:
                    if row[index] != '':
                        items_name |= {item_name.strip() for item_name in row[index].split(',')}
                for item_name in items_name:
                    if item_name in item_frequency:
                        item_frequency[item_name] += 1
                    else:
                        item_frequency[item_name] = 1

        for item_name, frequency in item_frequency.items():
            output.append([item_name, frequency, '', ''])
        with setting.absolute_name_map_file.open('w+', encoding='utf-8-sig', newline='') as f:
            writer = csv.writer(f)
            writer.writerows(output)

    # header = [原名, 频数, 目标名, 标签]
    def read_name_map(self, setting: Setting, tagger: Tagger) -> None:
        item_name_tags_map: dict[str, set[str]] = {}
        with setting.absolute_name_map_file.open('r', encoding='utf-8-sig') as f:
            reader = csv.reader(f)
            reader.__next__()
            for row in reader:
                name = row[0]
                if row[2] != '':
                    self.name_map[name] = row[2]
                    name = row[2]
                if row[3] != '':
                    item_name_tags_map[name] = {tag.strip() for tag in row[3].split(',')}
        tagger.set_item_name_tags_map(item_name_tags_map)



